//==================================================================
//  Copyright (C) 2006  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
/// @file m5d_material.h
///
/// @brief Material class.
///
//==================================================================

#ifndef M5D_MATERIAL_H
#define M5D_MATERIAL_H

#include "psys.h"
#include "psys_stdgfx.h"
#include "m5d_types.h"
#include "image_base.h"

//==================================================================
namespace M5D {

class Scene;

//==================================================================
///
//==================================================================
class RefCount
{
	int	_counter;
public:
	RefCount() :
		_counter(0)
	{
	}

	void	AddRef()
	{
		_counter += 1;
	}

	bool	DecRef()
	{
		PASSERT( _counter > 0 );
		_counter -= 1;
		if ( _counter == 0 )
			return true;
		else
			return false;
	}
};

//==================================================================
/// Texture class. 
//==================================================================
class Texture : private RefCount, public PSYS::sync_obj
{
public:
	Scene				*_scenep;
	void				*_userdatap;

private:
	PUtils::ImageBase	_image_base;
	bool				_is_transparent;

	//--------------------------------------------------------------
public:
	const static int	NAME_MAXLEN = 64;

	//--------------------------------------------------------------
	char					_name[NAME_MAXLEN];
	TCHAR					_filename[256];

	PSYSGFX::TexFilterMode	_filter_mode;
	PSYSGFX::TexAddrMode	_s_addr_mode;
	PSYSGFX::TexAddrMode	_t_addr_mode;

	//--------------------------------------------------------------
private:
	Texture( Scene *scenep, const char *namep, const TCHAR *filenamep=NULL, PUtils::ImageBase::LoadParams *load_paramsp=NULL );
	Texture( Scene *scenep, const char *namep, PUtils::Memfile &mf, const TCHAR *filenamep, PUtils::ImageBase::LoadParams *load_paramsp=NULL );
	Texture( Scene *scenep, const char *namep, int w, int h, PUtils::ImageBase::BaseFormat format );
	~Texture();

public:
	void		SetName_( const char *namep );
	void		SetFileName( const TCHAR *filenamep );

	const TCHAR	*GetFileName() const	{	return _filename;	}
	TCHAR		*GetFileName()			{	return _filename;	}

	PUtils::ImageBase	*GetImageBase()
	{
		return &_image_base;
	}

	const PUtils::ImageBase	*GetImageBase() const
	{
		return &_image_base;
	}

	bool		IsTransparent() const
	{
		return _is_transparent;
	}

	friend class Material;
	friend class Scene;
};

//==================================================================
/// Material class.
//==================================================================
class Material : public PSYS::sync_obj
{
public:
	Scene		*_scenep;
	void		*_userdatap;

	//--------------------------------------------------------------
public:
	const static int	NAME_MAXLEN				= 64;
	const static int	FLG_TMPMARK1			= 128;
	const static int	FLG_CHECK_FOR_DELETION	= 256;

	//--------------------------------------------------------------
	char				_name[NAME_MAXLEN];

	M5D::Texture		*_texturep;
	PMath::Vector4		_diffuse;
	PMath::Vector3		_specular, _emissive;
	float				_shininess, _reflection;
	u_int				_flags;
	PSYSGFX::BasicBlend	_basic_blend;
	bool				_write_depth;
	u_short				_tex_crop_u1, _tex_crop_v1;
	u_short				_tex_crop_u2, _tex_crop_v2;

	//--------------------------------------------------------------
private:
	Material( Scene *scenep, const char *namep = NULL );
public:
	~Material();

public:
	void			SetTexture( Texture *texturep );
	Texture			*GetTexture()						{ return _texturep; }
	const Texture	*GetTexture() const					{ return _texturep; }

	void			SetBasicBlend( PSYSGFX::BasicBlend basic_blend )	{ _basic_blend = basic_blend; }
	PSYSGFX::BasicBlend		GetBasicBlend() const					{ return _basic_blend; }
	bool			IsOpaque() const						{ return _basic_blend == PSYSGFX::BASICBLEND_OPAQUE; }

	void			SetShininess( float shininess )			{ _shininess = shininess; };
	void			SetReflection( float reflection )		{ _reflection = reflection; };
	float			GetShininess() const					{ return _shininess; };
	float			GetReflection() const					{ return _reflection; };

	void			SetName( const char *namep );
	void			SetDiffuseCol( float r, float g, float b, float a )	{	_diffuse.Set( r, g, b, a );	}
	void			SetDiffuseCol( const PMath::Vector4 &col )					{	_diffuse = col;				}
	void			SetSpecularCol( float r, float g, float b )			{	_specular.Set( r, g, b );	}
	void			SetSpecularCol( const PMath::Vector3 &col )				{	_specular = col;			}
	void			SetEmissiveCol( float r, float g, float b )			{	_emissive.Set( r, g, b );	}
	void			SetEmissiveCol( const PMath::Vector3 &col )				{	_emissive = col;			}

	void			SetWriteDepth( bool onoff )	{	_write_depth = onoff; }
	bool			IsWriteDepth() const		{	return _write_depth; }

	PMath::Vector4 &GetDiffuseCol()				{	return _diffuse;	}
	PMath::Vector3 &GetSpecularCol()				{	return _specular;	}
	PMath::Vector3 &GetEmissiveCol()				{	return _emissive;	}
	const PMath::Vector4 &GetDiffuseCol() const	{	return _diffuse;	}
	const PMath::Vector3 &GetSpecularCol() const	{	return _specular;	}
	const PMath::Vector3 &GetEmissiveCol() const	{	return _emissive;	}

	friend class Mesh;
	friend class PntSprt;
	friend class Scene;
};
typedef autodel<Material>	Material_SP;

};

#endif